unit Main;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, StdCtrls;

const
  // input and out buffer size constants...
  BufferInSize = 64;
  BufferOutSize = 64;

  // vendor and product ID constants...
  VENDOR_ID = $0411;
  PRODUCT_ID = $5750;
  IN_REPORT_ID = $01;
  OUT_REPORT_ID = $07;

type
  // input and output buffers...
  TBufferIn = array [0 .. BufferInSize] of byte;
  TBufferOut = array [0 .. BufferOutSize] of byte;

type
  TForm1 = class(TForm)
    PollFreq: TTimer;
    Status: TLabel;
    GetFreq: TButton;
    MonitorFreq: TCheckBox;
    ValueFreq: TComboBox;
    Label1: TLabel;
    Label2: TLabel;
    SetFreq: TButton;
    procedure PollFreqTimer(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure GetFreqClick(Sender: TObject);
    procedure SetFreqClick(Sender: TObject);
    procedure MonitorFreqClick(Sender: TObject);

  private
    { Private declarations }
    FBufferIn: TBufferIn;
    FBufferOut: TBufferOut;
    function USBEvent(var Msg: TMessage): Boolean;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  DeviceConnect: Boolean;
  SentCommand: byte;

const
  // command
  CMD_NULL = 0;
  CMD_POLLING = 1;
  CMD_GET_FREQUENCY = 2;
  CMD_SET_FREQUENCY = 3;

implementation

{$R *.dfm}

uses
  cUSBInterface,
  cUSBInterfaceTypes;

procedure SendDataArray(DataBuff: array of byte; len: integer;
  SendBuff: array of byte);
var
  DevHandle: cardinal;
  i: integer;
begin
  if DeviceConnect = True then
  begin
    for i := 0 to len - 1 do
    begin
      SendBuff[i + 1] := DataBuff[i];
    end;
    SendBuff[0] := IN_REPORT_ID;
    DevHandle := GetHandle(VENDOR_ID, PRODUCT_ID);
    Write(DevHandle, @SendBuff);
  end;
end;

procedure SendDataString(str: string; SendBuff: array of byte);
var
  DevHandle: cardinal;
  i: integer;
begin
  if length(str) < 64 then
  begin
    for i := 1 to length(str) do
    begin
      SendBuff[i] := ord(str[i]);
    end;
    SendBuff[0] := IN_REPORT_ID;
    DevHandle := GetHandle(VENDOR_ID, PRODUCT_ID);
    Write(DevHandle, @SendBuff);
  end;
end;

Function strtohex(s: string): byte;
var
  k1, k2: byte;
begin
  k1 := 0;
  k2 := 0;
  case s[1] of
    '0':
      k1 := $00;
    '1':
      k1 := $10;
    '2':
      k1 := $20;
    '3':
      k1 := $30;
    '4':
      k1 := $40;
    '5':
      k1 := $50;
    '6':
      k1 := $60;
    '7':
      k1 := $70;
    '8':
      k1 := $80;
    '9':
      k1 := $90;
    'A':
      k1 := $A0;
    'B':
      k1 := $B0;
    'C':
      k1 := $C0;
    'D':
      k1 := $D0;
    'E':
      k1 := $E0;
    'F':
      k1 := $F0;
  end;
  case s[2] of
    '0':
      k2 := $00;
    '1':
      k2 := $01;
    '2':
      k2 := $02;
    '3':
      k2 := $03;
    '4':
      k2 := $04;
    '5':
      k2 := $05;
    '6':
      k2 := $06;
    '7':
      k2 := $07;
    '8':
      k2 := $08;
    '9':
      k2 := $09;
    'A':
      k2 := $0A;
    'B':
      k2 := $0B;
    'C':
      k2 := $0C;
    'D':
      k2 := $0D;
    'E':
      k2 := $0E;
    'F':
      k2 := $0F;
  end;
  strtohex := k1 or k2;
end;

Function hextostr(i: byte): String;
var
  k1, k2: byte;
  sstr, str2: string;
begin
  k1 := i and $F0;
  k2 := i and $0F;
  case k1 of
    $00:
      sstr := '0';
    $10:
      sstr := '1';
    $20:
      sstr := '2';
    $30:
      sstr := '3';
    $40:
      sstr := '4';
    $50:
      sstr := '5';
    $60:
      sstr := '6';
    $70:
      sstr := '7';
    $80:
      sstr := '8';
    $90:
      sstr := '9';
    $A0:
      sstr := 'A';
    $B0:
      sstr := 'B';
    $C0:
      sstr := 'C';
    $D0:
      sstr := 'D';
    $E0:
      sstr := 'E';
    $F0:
      sstr := 'F';
  end;
  case k2 of
    $00:
      str2 := '0';
    $01:
      str2 := '1';
    $02:
      str2 := '2';
    $03:
      str2 := '3';
    $04:
      str2 := '4';
    $05:
      str2 := '5';
    $06:
      str2 := '6';
    $07:
      str2 := '7';
    $08:
      str2 := '8';
    $09:
      str2 := '9';
    $0A:
      str2 := 'A';
    $0B:
      str2 := 'B';
    $0C:
      str2 := 'C';
    $0D:
      str2 := 'D';
    $0E:
      str2 := 'E';
    $0F:
      str2 := 'F';
  end;
  hextostr := sstr + str2;
end;

procedure TForm1.PollFreqTimer(Sender: TObject);
var
  OutData: array [0 .. BufferOutSize] of byte;
begin
  if DeviceConnect = true then
  begin
    OutData[0] := CMD_POLLING;
    SendDataArray(OutData, BufferOutSize, FBufferOut);
    SentCommand := CMD_POLLING;
  end;
end;

procedure TForm1.SetFreqClick(Sender: TObject);
var
  OutData: array [0 .. BufferOutSize] of byte;
begin
  if DeviceConnect = true then
  begin
    OutData[0] := CMD_SET_FREQUENCY;
    if (ValueFreq.ItemIndex >= 0) and (ValueFreq.ItemIndex <= 99) then
      OutData[1] := ValueFreq.ItemIndex + 1
    else
    begin
      OutData[1] := 39 + 1;
      ValueFreq.ItemIndex := 39;
    end;
    OutData[2] := 0;
    SendDataArray(OutData, BufferOutSize, FBufferOut);
    SentCommand := CMD_SET_FREQUENCY;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Application.HookMainWindow(USBEvent);
  Connect(Application.Handle);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  Application.UnHookMainWindow(USBEvent);
end;

procedure TForm1.GetFreqClick(Sender: TObject);
var
  OutData: array [0 .. BufferOutSize] of byte;
begin
  if DeviceConnect = true then
  begin
    OutData[0] := CMD_GET_FREQUENCY;
    SendDataArray(OutData, BufferOutSize, FBufferOut);
    SentCommand := CMD_GET_FREQUENCY;
  end;
end;

procedure TForm1.MonitorFreqClick(Sender: TObject);
begin
  if MonitorFreq.Checked = true then
  begin
    PollFreq.Enabled := true;
    SetFreq.Enabled := false;
    GetFreq.Enabled := false;
  end
  else
  begin
    PollFreq.Enabled := false;
    SetFreq.Enabled := true;
    GetFreq.Enabled := true;
  end;
end;

{
  ****************************************************************************
  * Name    : USBEvent                                                       *
  * Purpose : DLL message handler hook                                       *
  ****************************************************************************
}
function TForm1.USBEvent(var Msg: TMessage): Boolean;
var
  DevHandle: cardinal;
begin
  result := False;
  if Msg.Msg = WM_HID_EVENT then
  begin
    case Msg.WParam of

      // a HID device has been plugged in...
      NOTIFY_PLUGGED:
        begin
          // is it our HID device...
          DevHandle := Msg.LParam; // handle of HID device in this message
          if (GetVendorID(DevHandle) = VENDOR_ID) and
            (GetProductID(DevHandle) = PRODUCT_ID) then
          begin
            // add your code here, for example...
            DeviceConnect := true;
            Status.Caption := 'Device Connected';
          end;
          result := true;
        end;

      // a HID device has been device removed...
      NOTIFY_UNPLUGGED:
        begin
          // is it our HID device...
          DevHandle := Msg.LParam; // handle of HID device in this message
          if (GetVendorID(DevHandle) = VENDOR_ID) and
            (GetProductID(DevHandle) = PRODUCT_ID) then
          begin
            // add you code here
            DeviceConnect := False;
            Status.Caption := 'Device Disconnected';
          end;
          result := true;
        end;

      // a HID device has been attached or removed. This event is fired after
      // either NotifyPlugged or NotifyUnplugged.
      NOTIFY_CHANGED:
        begin
          // get the handle of the device we are interested in
          // and set it's read notification flag to true...
          DevHandle := GetHandle(VENDOR_ID, PRODUCT_ID);
          SetReadNotify(DevHandle, true);
          result := true;
        end;

      // a HID device has sent some data..
      NOTIFY_READ:
        begin
          DevHandle := Msg.LParam; // handle of HID device in this message
          if (GetVendorID(DevHandle) = VENDOR_ID) and
            (GetProductID(DevHandle) = PRODUCT_ID) then
          begin
            // read the data - remember that first byte is report ID...
            Read(DevHandle, @FBufferIn);

            // process data here...
            if FBufferIn[0] = OUT_REPORT_ID then
            begin
              case SentCommand of
              CMD_POLLING:
                begin
                  if (FBufferIn[1] = ord('A')) and (FBufferIn[2] >= 1) and (FBufferIn[2] <= 100) then
                  begin
                    ValueFreq.ItemIndex := FBufferIn[2] - 1;
                  end;
                end;

              CMD_GET_FREQUENCY:
                begin
                  if (FBufferIn[1] = ord('A')) and (FBufferIn[2] >= 1) and (FBufferIn[2] <= 100) then
                  begin
                    ValueFreq.ItemIndex := FBufferIn[2] - 1;
                  end;
                end;

              CMD_SET_FREQUENCY:
                begin
                  if (FBufferIn[1] = ord('A')) then
                  begin
                    Status.Caption := 'Set Frequency: Done';
                  end
                  else
                  begin
                    Status.Caption := 'Set Frequency: Fail';
                  end;
                end;

              end;
            end;

          end;
        end;
    end;
  end;
end;

end.
